/*
 * Copyright (c) 2009, Hamish Morgan
 * All rights reserver.
 */
package locusts.common.behaviours;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import javax.vecmath.Vector2d;
import locusts.common.entities.Vehicle;
import locusts.lib.MathUtil;

/**
 * BehaviourList is a special behaviour that allows a number of
 * behaviours to be combined. For example averaged.
 *
 * @author Hamish Morgan
 */
public abstract class BehaviourList extends AbstractBehaviour
        implements Collection<Behaviour> {

    protected final List<Behaviour> behaviours;

    public BehaviourList(List<Behaviour> behaviours) {
        this.behaviours = behaviours;
    }

    public BehaviourList() {
        this(new ArrayList<Behaviour>());
    }

    abstract public Vector2d getSteering(Vehicle boid);

    protected Vector2d[] getForces(Vehicle boid) {
        Vector2d[] forces = new Vector2d[behaviours.size()];

        for (int i = 0; i <
                behaviours.size(); i++)
            forces[i] = behaviours.get(i).getSteering(boid);
        return forces;

    }

    public static class Max extends BehaviourList {

        @Override
        public Vector2d getSteering(Vehicle boid) {
            Vector2d[] forces = getForces(boid);
            Vector2d steering = MathUtil.max(forces);
            steering.scale(getWeight());
            return steering;

        }
    }

    public static class Average extends BehaviourList {

        @Override
        public Vector2d getSteering(Vehicle boid) {
            Vector2d[] forces = getForces(boid);
            Vector2d steering = MathUtil.average(forces);
            return steering;

        }
    }

    public static class Accumulate extends BehaviourList {

        private double limit;

        public Accumulate(double limit) {
            this.limit = limit;
        }

        @Override
        public Vector2d getSteering(Vehicle boid) {
            Vector2d[] forces = getForces(boid);
            Vector2d steering = MathUtil.accumulate(forces, limit);
            return steering;
        }
    }

    @Override
    public boolean add(Behaviour arg0) {
        return behaviours.add(arg0);
    }

    @Override
    public int size() {
        return behaviours.size();
    }

    public boolean isEmpty() {
        return behaviours.isEmpty();
    }

    public boolean contains(Object arg0) {
        return behaviours.contains(arg0);
    }

    public Iterator<Behaviour> iterator() {
        return behaviours.iterator();
    }

    public Object[] toArray() {
        return behaviours.toArray();
    }

    public <T> T[] toArray(T[] arg0) {
        return behaviours.toArray(arg0);
    }

    public boolean remove(Object arg0) {
        return behaviours.remove(arg0);
    }

    public boolean containsAll(Collection<?> arg0) {
        return behaviours.containsAll(arg0);
    }

    public boolean addAll(Collection<? extends Behaviour> arg0) {
        return behaviours.addAll(arg0);
    }

    public boolean removeAll(Collection<?> arg0) {
        return behaviours.removeAll(arg0);
    }

    public boolean retainAll(Collection<?> arg0) {
        return behaviours.retainAll(arg0);
    }

    public void clear() {
        behaviours.clear();
    }
}
